import requests
from requests import Response

from DialogDiagnosis.DataService.model import NulUsers
from .token import *


class WxSession:
    def __init__(self, openid: str, session_key: str, unionid: str):
        self.openid: str = openid
        self.session_key: str = session_key
        self.unionid: str = unionid


class LoginResult(Result):
    def __init__(self, token: str, new_user: bool):
        super().__init__()
        self.token: str = token
        self.new_user: bool = new_user

    def serialize(self) -> dict:
        dictionary: dict = {
            'token': self.token,
            'new_user': self.new_user
        }
        return dictionary


def get_session_by_code(code: str) -> WxSession:
    url: str = 'https://api.weixin.qq.com/sns/jscode2session'
    params: dict = {
        'appid': APP_ID,
        'secret': APP_SECRET,
        'js_code': code,
        'grant_type': 'authorization_code'
    }
    result: Response = requests.get(url, params=params)
    result_json: dict = result.json()

    errcode = result_json.get('errcode')
    if errcode and errcode != 0:
        errmsg: str = result_json.get('errmsg')

        if errcode == -1:
            raise NulException(ERR_SYSTEM_BUSY, errmsg)
        elif errcode == 40029:
            raise NulException(ERR_LOGIN_INVALID_CODE, errmsg)
        elif errcode == 45011:
            raise NulException(ERR_LOGIN_REQUEST_TOO_FREQUENT, errmsg)
        elif errcode == 40226:
            raise NulException(ERR_LOGIN_HIGH_RISK, errmsg)
        else:
            raise NulException(ERR_UNKNOWN_ERROR, f"Unknown error #{errcode}: ${errmsg}")

    openid: str = result_json.get('openid')
    session_key: str = result_json.get('session_key')
    unionid: str = result_json.get('unionid')

    if not unionid:
        unionid = ''

    return WxSession(openid, session_key, unionid)


def check_user_existence(openid: str, unionid: str) -> bool:
    count: int = NulUsers.objects.filter(OpenID__exact=openid, UnionID__exact=unionid).count()
    return count > 0


def register_user(openid: str, unionid: str) -> None:
    user: NulUsers = NulUsers(OpenID=openid, UnionID=unionid)
    user.save()
    return


def login(request: HttpRequest) -> JsonResponse:
    try:
        body: dict = decode_std_body(request)

        code: str = get_json_value_or_except(body, 'code', str)
        session: WxSession = get_session_by_code(code)
        token: str = generate_token(session.openid, session.unionid)

        new_user: bool = not check_user_existence(session.openid, session.unionid)
        if new_user:
            register_user(session.openid, session.unionid)

    except NulException as e:
        return response_except(e)

    return response(LoginResult(token, new_user))


